﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xenta.Api;
using Xenta.Entities;
using Xenta.Enums;
using Xenta.Plugins;
using Xenta.Security;
using Xenta.Utils;

namespace Xenta.Operations
{
    #region __General__

    /// <summary>
    /// Creates a message template.
    /// </summary>
    public class CreateMessageTemplate : CreateAuditable<MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        /// <summary>
        /// Gets or sets the sender unique identifier.
        /// </summary>
        public Guid SenderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        public string Code
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sender address.
        /// </summary>
        public string From
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the recipient address.
        /// </summary>
        public string To
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the BCC recipient address.
        /// </summary>
        public string BccTo
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the address where to reply to.
        /// </summary>
        public string ReplyTo
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public MessageTemplateFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Code))
                return Err.Of<MessageTemplateEntity>().NotValid("Code");
            if(!uow.Infrastructure.CheckDependency<IMessageSender>(SenderID))
                return Err.Of<IMessageSender>().NotFound();
            return base.Validate(uow);
        }

        protected override void Construct(IUnitOfWork uow, MessageTemplateEntity entity)
        {
            base.Construct(uow, entity);

            entity.SenderID = SenderID;
            entity.Code = Code.TrimToLen(10);
            entity.From = StringHelper.EnsureNotNull(From).TrimToLen(100);
            entity.To = StringHelper.EnsureNotNull(To).TrimToLen(100);
            entity.BccTo = StringHelper.EnsureNotNull(BccTo).TrimToLen(100);
            entity.ReplyTo = StringHelper.EnsureNotNull(ReplyTo).TrimToLen(100);
            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Updates the message template.
    /// </summary>
    public class UpdateMessageTemplate : UpdateAuditable<MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        /// <summary>
        /// Gets or sets the sender unique identifier.
        /// </summary>
        public Guid SenderID
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the code.
        /// </summary>
        public string Code
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sender address.
        /// </summary>
        public string From
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the recipient address.
        /// </summary>
        public string To
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the BCC recipient address.
        /// </summary>
        public string BccTo
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the address where to reply to.
        /// </summary>
        public string ReplyTo
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        public MessageTemplateFlags Flags
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override Err Validate(IUnitOfWork uow)
        {
            if(String.IsNullOrWhiteSpace(Code))
                return Err.Of<MessageTemplateEntity>().NotValid("Code");
            if(!uow.Infrastructure.CheckDependency<IMessageSender>(SenderID))
                return Err.Of<IMessageSender>().NotFound();
            return base.Validate(uow);
        }

        protected override void Revise(IUnitOfWork uow, MessageTemplateEntity entity)
        {
            base.Revise(uow, entity);

            entity.SenderID = SenderID;
            entity.Code = Code.TrimToLen(10);
            entity.From = StringHelper.EnsureNotNull(From).TrimToLen(100);
            entity.To = StringHelper.EnsureNotNull(To).TrimToLen(100);
            entity.BccTo = StringHelper.EnsureNotNull(BccTo).TrimToLen(100);
            entity.ReplyTo = StringHelper.EnsureNotNull(ReplyTo).TrimToLen(100);
            entity.Flags = Flags;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the message template.
    /// </summary>
    public class DeleteMessageTemplate : DeleteEntity<MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        #endregion

        #region Utilities

        protected override void Destruct(IUnitOfWork uow, MessageTemplateEntity entity)
        {
            foreach(var i in entity.Translations)
            {
                uow.Execute(new DeleteMessageTemplateTranslation
                {
                    EntityID = i.EntityID
                });
            }
            base.Destruct(uow, entity);
        }

        #endregion
    }

    /// <summary>
    /// Gets the message template by identifier.
    /// </summary>
    public class GetMessageTemplate : GetEntity<MessageTemplateEntity>,
        IApiOperation
    {
    }

    /// <summary>
    /// Gets the message template by code.
    /// </summary>
    public class GetMessageTemplateByCode : QueryEntity<MessageTemplateEntity>,
        IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets or sets the template code.
        /// </summary>
        public string Code
        {
            get;
            set;
        }

        #endregion

        #region Options

        protected override bool Cacheable
        {
            get
            {
                return true;
            }
        }

        #endregion

        #region Utilities

        protected override IQueryable<MessageTemplateEntity> Build(IUnitOfWork uow, IQueryable<MessageTemplateEntity> query)
        {
            string code = StringHelper.EnsureNotNull(Code).TrimToLen(10);
            return base.Build(uow, query).Where(x => x.Code.Equals(code));
        }

        #endregion
    }

    #endregion

    #region __Translation__

    /// <summary>
    /// Creates a template translation.
    /// </summary>
    public class CreateMessageTemplateTranslation : CreateTranslation
        <TMessageTemplateEntity, MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        /// <summary>
        /// Gets or sets the subject.
        /// </summary>
        public string Subject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Construct(IUnitOfWork uow, TMessageTemplateEntity entity)
        {
            base.Construct(uow, entity);

            entity.Subject = StringHelper.EnsureNotNull(Subject).TrimToLen(100);
            entity.Text = StringHelper.EnsureNotNull(Text);
        }

        #endregion
    }

    /// <summary>
    /// Updates the template translation.
    /// </summary>
    public class UpdateMessageTemplateTranslation : UpdateTranslation
        <TMessageTemplateEntity, MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        /// <summary>
        /// Gets or sets the subject.
        /// </summary>
        public string Subject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Revise(IUnitOfWork uow, TMessageTemplateEntity entity)
        {
            base.Revise(uow, entity);

            entity.Subject = StringHelper.EnsureNotNull(Subject).TrimToLen(100);
            entity.Text = StringHelper.EnsureNotNull(Text);
        }

        #endregion
    }

    /// <summary>
    /// Saves a template translation.
    /// </summary>
    public class SaveMessageTemplateTranslation : SaveTranslation
        <TMessageTemplateEntity, MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        /// <summary>
        /// Gets or sets the subject.
        /// </summary>
        public string Subject
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override void Work(IUnitOfWork uow, out TMessageTemplateEntity result)
        {
            var translation = uow.Execute(new GetMessageTemplateTranslationByLanguage
            {
                HolderID = HolderID,
                LanguageID = LanguageID
            }).Result;
            if(translation == null)
            {
                translation = uow.Execute(new CreateMessageTemplateTranslation
                {
                    HolderID = HolderID,
                    LanguageID = LanguageID,
                    Subject = Subject,
                    Text = Text
                }).Result;
            }
            else
            {
                translation = uow.Execute(new UpdateMessageTemplateTranslation
                {
                    EntityID = translation.EntityID,
                    LanguageID = LanguageID,
                    Subject = Subject,
                    Text = Text
                }).Result;
            }
            result = translation;
        }

        #endregion
    }

    /// <summary>
    /// Deletes the template translation.
    /// </summary>
    public class DeleteMessageTemplateTranslation : DeleteTranlsation
        <TMessageTemplateEntity, MessageTemplateEntity>,
        ISecuredOperation, IApiOperation
    {
        #region Properties

        /// <summary>
        /// Gets the collection of security policies.
        /// </summary>
        public IEnumerable<SecurityPolicy> SecurityPolicies
        {
            get
            {
                yield return new SecurityPolicy()
                    .IsAuthenticated()
                    .HasPermission("MSG");
            }
        }

        #endregion
    }

    /// <summary>
    /// Gets the template translation.
    /// </summary>
    public class GetMessageTemplateTranslation : GetTranlsation
        <TMessageTemplateEntity, MessageTemplateEntity>,
        IApiOperation
    {
    }

    /// <summary>
    /// Gets the template translation.
    /// </summary>
    public class GetMessageTemplateTranslationByLanguage : GetTranlsationByLanguage
        <TMessageTemplateEntity, MessageTemplateEntity>,
        IApiOperation
    {
    }

    #endregion

    #region __Search__

    /// <summary>
    /// Search over message template collection.
    /// </summary>
    public class SearchMessageTemplates : SearchOperation<MessageTemplateEntity>,
        IApiOperation
    {
        #region Ctors

        /// <summary>
        /// Initializes a new class instance.
        /// </summary>
        public SearchMessageTemplates()
        {
            SortDir = SortDirection.Ascending;
            SortBy = new []
            {
                MessageTemplateSortBy.ID
            };
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the flag mask.
        /// </summary>
        public MessageTemplateFlags FlagMask
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sort direction.
        /// </summary>
        public SortDirection SortDir
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the sort by.
        /// </summary>
        public MessageTemplateSortBy[] SortBy
        {
            get;
            set;
        }

        #endregion

        #region Utilities

        protected override IQueryable<MessageTemplateEntity> Build(IUnitOfWork uow, IQueryable<MessageTemplateEntity> query)
        {
            query = base.Build(uow, query);
            query = query.FilterByFlags(x => (int)x.Flags, (int)FlagMask);
            if(SortBy != null)
            {
                for(int i = 0; i < SortBy.Length; i++)
                {
                    switch(SortBy[i])
                    {
                        case MessageTemplateSortBy.From:
                            query = query.OrderBy(x => x.From, SortDir, i != 0);
                            break;
                        case MessageTemplateSortBy.To:
                            query = query.OrderBy(x => x.To, SortDir, i != 0);
                            break;
                        case MessageTemplateSortBy.Code:
                            query = query.OrderBy(x => x.Code, SortDir, i != 0);
                            break;
                        case MessageTemplateSortBy.CreatedOn:
                            query = query.OrderBy(x => x.CreatedOn, SortDir, i != 0);
                            break;
                        default:
                            query = query.OrderBy(x => x.EntityID, SortDir, i != 0);
                            break;
                    }
                }
            }
            return query;
        }

        #endregion
    }

    #endregion
}
